const installed = Symbol.for("VueRouter");
const CONFIG = {
  [installed]: false,
};
let _Vue;

const init = Symbol("init");
const initRouteMap = Symbol("initRouteMap");
const initComponent = Symbol("initComponent");
const initEvent = Symbol("initEvent");
const genRouterLink = Symbol("genRouterLink");
const genRouterView = Symbol("genRouterView");

export default class VueRouter {
  static install(Vue) {
    if (CONFIG[installed]) return;
    CONFIG[installed] = true;
    _Vue = Vue;
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
        }
      },
    });
  }

  constructor(options) {
    if (!_Vue) throw Error("VueRouter must installed");
    this.options = options;
    this.routeMap = {};
    this.prefix = this.options.mode === "hash" ? "/#" : "";
    this.data = _Vue.observable({
      current: "/",
    });
    this[init]();
  }

  [init]() {
    this[initRouteMap]();
    this[initComponent]();
    this[initEvent]();
  }

  [initRouteMap]() {
    if (Array.isArray(this.options.routes)) {
      this.options.routes.forEach((route) => {
        this.routeMap[route.path] = route.component;
      });
    }
  }

  [initComponent]() {
    this[genRouterLink]();
    this[genRouterView]();
  }

  [genRouterLink]() {
    const prefix = this.prefix;
    _Vue.component("router-link", {
      props: {
        to: String,
      },
      render(h) {
        return h(
          "a",
          {
            attrs: {
              href: this.to,
            },
            on: {
              click: this.clickHandler,
            },
          },
          this.$slots.default
        );
      },
      methods: {
        clickHandler(evt) {
          evt.preventDefault();
          const routePath = this.convertPath(this.to);
          history.pushState({}, "", routePath);
          this.$router.data.current = this.to;
        },
        convertPath(path) {
          const routePath = path.startsWith("/") ? path : `/${path}`;
          return `${prefix}${routePath}`;
        },
      },
    });
  }

  [genRouterView]() {
    const self = this;
    _Vue.component("router-view", {
      render(h) {
        const component = self.routeMap[self.data.current];
        return h(component);
      },
    });
  }

  [initEvent]() {
    const self = this;
    // window.addEventListener("popstate", () => {
    //   self.data.current = location.pathname;
    // });
    window.addEventListener("hashchange", () => {
      const hash = location.hash;
      const path = hash.startsWith("#") ? hash.slice(1) : hash;
      self.data.current = path;
    });
  }
}

